<html>
    <head>
        <title>状态管理</title>
    </head>
    <body>
        <script>
            // 状态管理

                        /*
                            随着你的应用的增长，更有意识地了解你的状态是如何组织的以及数据如何在你的组件之间流动是很有帮助的。

                            冗余或者重复状态是错误的常见来源。
                        */


                    // 一、使用状态对输出做出反应
                               /*
                                    使用React，你不会直接从代码修改UI。比如你不会写"禁用按钮"、"启用按钮"、"显示成功信息"等命令，
                                    而是真对你的组件的不同视觉状态("初始状态"、"键入状态"、"成功状态")描述你想看到的UI，然后触发状态响应用户输入的变化。
                                    这类似于UI设计师对UI的看法。
                               */

                               /*
                                    这是一个实用rect构建的测验表单。请注意，它如何使用status状态变量来确定是启用还是禁用提交按钮，以及是否显示成功消息。
                               */
                                        import { useState } from 'react';

                                        export default function Form() {
                                                    const [answer, setAnswer] = useState('');
                                                    const [error, setError] = useState(null);
                                                    const [status, setStatus] = useState('typing');

                                                    if (status === 'success') {
                                                        return <h1>That's right!</h1>
                                                    }

                                                    async function handleSubmit(e) {
                                                        e.preventDefault();
                                                        setStatus('submitting');
                                                        try {
                                                        await submitForm(answer);
                                                        setStatus('success');
                                                        } catch (err) {
                                                        setStatus('typing');
                                                        setError(err);
                                                        }
                                                    }

                                                    function handleTextareaChange(e) {
                                                        setAnswer(e.target.value);
                                                    }

                                                    return (
                                                        <>
                                                        <h2>City quiz</h2>
                                                        <p>
                                                            In which city is there a billboard that turns air into drinkable water?
                                                        </p>
                                                        <form onSubmit={handleSubmit}>
                                                            <textarea
                                                                value={answer}
                                                                onChange={handleTextareaChange}
                                                                disabled={status === 'submitting'}
                                                            />
                                                            <br />
                                                            <button disabled={  // 这里通过 status 状态来判断是否有禁用按钮
                                                                answer.length === 0 ||
                                                                status === 'submitting'
                                                            }>
                                                                Submit
                                                            </button>
                                                            {error !== null &&
                                                                <p className="Error">
                                                                    {error.message}
                                                                </p>
                                                            }
                                                        </form>
                                                        </>
                                                    );
                                        }

                                        function submitForm(answer) {
                                            // Pretend it's hitting the network.
                                            return new Promise((resolve, reject) => {
                                                setTimeout(() => {
                                                    let shouldError = answer.toLowerCase() !== 'lima'
                                                    if (shouldError) {
                                                        reject(new Error('Good guess but a wrong answer. Try again!'));
                                                    } else {
                                                        resolve();
                                                    }
                                                }, 1500);
                                            });
                                        }


                    // 二、选择状态结构
                                /*
                                    良好地构建状态可以区分易于修改和调试的组件，以及一个江场产生错误的组件。
                                    最重要的原则是状态不应该包含冗余或重复的信息。
                                    如果有不必要的状态，很容易忘记更新它，并引入错误！
                                */

                                    // 例如，此形式有一个冗余的 fullName 状态变量：
                                        import { useState } from 'react';

                                        export default function Form() {
                                            const [firstName, setFirstName] = useState('');
                                            const [lastName, setLastName] = useState('');

                                            // 冗余状态，你可以通过在组件渲染时计算 fullName 来避免冗余。
                                            // 这似乎是一个小改动，但React应用中的许多错误都是通过这种方式修复的。
                                            const [fullName, setFullName] = useState('');  

                                            function handleFirstNameChange(e) {
                                                setFirstName(e.target.value);
                                                setFullName(e.target.value + ' ' + lastName);
                                            }

                                            function handleLastNameChange(e) {
                                                setLastName(e.target.value);
                                                setFullName(firstName + ' ' + e.target.value);
                                            }

                                            return (
                                                <>
                                                    <h2>Let’s check you in</h2>
                                                    <label>
                                                        First name:{' '}
                                                        <input
                                                            value={firstName}
                                                            onChange={handleFirstNameChange}
                                                        />
                                                    </label>
                                                    <label>
                                                        Last name:{' '}
                                                        <input
                                                            value={lastName}
                                                            onChange={handleLastNameChange}
                                                        />
                                                    </label>
                                                    <p>
                                                        Your ticket will be issued to: <b>{fullName}</b>
                                                    </p>
                                                </>
                                            );
                                        }
                      
                    
                    // 三、在组件之间共享状态
                                    /*
                                        有时，你希望两个组件的状态始终一起更改。
                                        要做到这一点，从他们两个中"删除状态"，将其移动到他们最近的共同父级组件，
                                        然后"通过属性"将"共同父级的状态值"其传递给他们。 
                                        这被称为"提升状态"，它是你编写React代码时最常做的事情之一。
                                    */
                                        import {useState} from 'react';
                                        function Panel({title,children,isActive,onShow}){
                                            return (
                                                <section>
                                                    <h3>{title}</h3>
                                                    {isActive?(
                                                        <p>{children}</p>
                                                    ):(
                                                        <button onClick={onShow}>
                                                            显示
                                                        </button>
                                                    )}
                                                </section>
                                            );
                                        }

                                        export default function Accordion(){
                                            const [activeIndex,setActiveIndex] = useState(0); // 此状态通过属性的方式传递给Panel组件

                                            return (
                                                <>
                                                    <h2>Almaty,Kazakhstan</h2>
                                                    <panel title="关于" isActive={activeIndex===0} onShow={()=>setActiveIndex(0)}>
                                                        阿拉木图人口约200万，是哈萨克斯坦最大的城市。在1929年至1997年之间，它是该国首都。
                                                    </panel>
                                                    <panel title="词源" isActive={activeIndex===1} onShow={()=>setActiveIndex(1)}>
                                                        这个名字源于哈萨克语 <span lang="kk-KZ">алма</span>，是“苹果”的意思，通常被翻译成“满是苹果”。
                                                        事实上，阿拉木图周围的地区被认为是苹果的祖籍，<i lang="la">Malus sieversii</i> 被认为是目前本土苹果的祖先。
                                                    </panel>
                                                </>

                                            );
                                        }   
                                        
                    // 四、保留和重置状态
                                        /*
                                            当你重新渲染一个组件时，React需要决定组件树中的哪部分需要保留和更新，以及丢弃或重新创建。
                                            在大多数情况下，React的自动机制已经做得足够好了。默认情况下，React会保留树中与先前渲染的组件树"匹配"的部分。

                                            然而，有时这并不是你想要的。
                                        */
                                            // eg:  下面的而例子中，输入内容后再切换收件人并不会清空输入框。这可能导致用户不小心发错消息：
                                                
                                                // Chat.js 文件：
                                                    import {useState} from 'react';
                                                    export default function Chat({contact}){
                                                        const [text,setText] = useSate('');
                                                        return (
                                                            <section>
                                                                <textarea value={text} placeholder={'Chat to'+contact.name} 
                                                                        onChange={e=>setText(e.target.value)}/>
                                                                <br />   
                                                                <button>发送给{contact.email}</button>
                                                            </section>
                                                        );
                                                    }

                                                // ContactList.js 文件：
                                                    export default function ContactList({
                                                        selectedContact,
                                                        contacts,
                                                        onSelect
                                                    }){
                                                        return(
                                                            <section className="contact-list">
                                                                <ul>
                                                                    {contacts.map(contact=>
                                                                        <li key={contact.email}>
                                                                            <button onClick={()=>onSelect(contact)}>
                                                                                {contact.name}
                                                                            </button>
                                                                        </li>
                                                                    )}
                                                                </ul>
                                                            </section>
                                                        );
                                                    }

                                                // App.js 文件：
                                                    import {useState} from 'react';
                                                    import Chat from './Chat';
                                                    import ContactList from './ContactList';
                                                    export default function Messager(){
                                                        const [to,setTo] =useState(contacts[0]);

                                                        return (
                                                            <div>
                                                                <ContactList
                                                                    selectedContact={to}
                                                                    contacts={contacts}
                                                                    onSelect={contact=>setTo(contact)}
                                                                />
                                                                <Chat key={to.email} contact={to}/>
                                                            </div>

                                                        );
                                                    }

                                                    const contacts=[
                                                        { name: 'Taylor', email: 'taylor@mail.com' },
                                                        { name: 'Alice', email: 'alice@mail.com' },
                                                        { name: 'Bob', email: 'bob@mail.com' }
                                                    ]

                                       
        </script>
    </body>
</html>